#define USE_X_RESULT

using System;
using System.Configuration;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Text;
using System.Web;
using System.Web.Services;
using System.Xml;

using log4net;
using umlungu.engineX.passportX;

/*	-----------------------------------------------------------------------	
	Copyright:	umlungu consulting (pty) ltd
	Author:		Alan Benington
	Started:	2007-05-27	
	Status:		redev	
	Version:	2.0.0
	Build:		20070911
	License:	GNU General Public License
	-----------------------------------------------------------------------	*/

/*	-------------------------------------------------------------------------------------------------
	Note re EngineX.PassportX:
	------------------------------------
	The refactoring mentioned below is intended to result in a code base that can be migrated
	into the EngineX framework as follows:
	- Base classes migrated to the EngineX.PassportX namespace.
	- Web Service classes migrated to the EngineX.PassportServiceX namespace.
	- Web service classes can remain in an implementation class (eg NashuaMobile.Gatekeeper)
	Note: Once this is completed the Gatekeeper code will become dependant on PassportX base classes.
		  If this is not desired, a fork in the codebase will be created at that stage.
	-------------------------------------------------------------------------------------------------	*/

/*	-------------------------------------------------------------------------------------------------
	Development Notes:
	20070911:	Starting point.
				Split the original PassportBaseX into this and PassportRootX
				- db methods/properties in PassportBaseX
				- xml and core methods/properties in PassportRootX
	20071220:	Made some WebMethods virtual to allow them to be overridden (ie hidden)
	-------------------------------------------------------------------------------------------------	*/

namespace umlungu.engineX.passportX.passportserviceX {
#if (!USE_X_RESULT)
	/// <summary>Description of the enumeration</summary>
	public enum PassportTypeX {
		/// <summary>identifier for GateKeeper type of services</summary>
	    GateKeeper = 1,
		/// <summary>identifier for Passport type of services</summary>
	    Passport = 2,
		/// <summary>identifier for Other type of services</summary>
		Other = 3
	}
#endif
	/// <summary>
	/// This PassportService class is
	/// </summary>
	[WebService(Namespace="urn:umlungu:enginex")]
#if USE_X_RESULT
	public class PassportRootX : umlungu.engineX.x_result {
#else
	public class PassportRootX : System.Web.Services.WebService {
#endif
		#region Invisible properties
#if (!USE_X_RESULT)
		private string resultxml;
#endif
		#endregion

		#region Constants
		private const string DEFAULT_TAG = "nm_service";

#if (!USE_X_RESULT)
		private const string RESULT_XML_GATEKEEPER = "<{0}><service><response><process><Transaction_Result><Result_Code>0</Result_Code><Description/>{1}</Transaction_Result></process></response></service></{0}>";
		private const string RESULT_XML_PASSPORT = "<{0}><Result><ResultCode>0</ResultCode><Description/></Result>{1}</{0}>";
		private const string RESULT_XML_OTHER = "<{0}><Result><Code>0</Code><Description/></Result>{1}</{0}>";
		
		private const string SELECT_DESC_GATEKEEPER = "//Transaction_Result/Description";
		private const string SELECT_DESC_PASSPORT = "Result/Description";
		private const string SELECT_DESC_OTHER = "//Result/Description";
		
		private const string SELECT_CODE_GATEKEEPER = "//Transaction_Result/Result_Code";
		private const string SELECT_CODE_PASSPORT = "Result/ResultCode";
		private const string SELECT_CODE_OTHER = "//Result/Code";
		
		private const string SELECT_RESULT_GATEKEEPER = "//Transaction_Result";
		private const string SELECT_RESULT_PASSPORT = "Result";
		private const string SELECT_RESULT_OTHER = "//Result";
#endif
		#endregion

		#region Visible properties
#if (!USE_X_RESULT)
		private string tag = DEFAULT_TAG;
		protected DateTime starttime;
		/// <summary>The name for the root document element</summary>
		/// <value>A string containing the tag</value>
		public string Tag {
			get { return tag; }
			set { tag = value; setType(); }
		}
		private PassportTypeX type;
		/// <summary>PassportX type</summary>
		/// <value>Type to identify GateKeeper or Passport type service</value>
		public PassportTypeX Type {
			get { return type; }
			set { type = value; }
		}
		private string result;
		/// <summary>Description of the result</summary>
		/// <value>The value of the description element/value>
		public XmlNode Result {
			get { return resultdoc.SelectSingleNode(result); }
		}
		private string code;
		/// <summary>Description of the result</summary>
		/// <value>The value of the description element/value>
		public string Code {
			get { return resultdoc.SelectSingleNode(code).InnerText; }
			set { resultdoc.SelectSingleNode(code).InnerText = value; }
		}
		private string description;
		/// <summary>Description of the result</summary>
		/// <value>The value of the description element/value>
		public string Description {
			get { return resultdoc.SelectSingleNode(description).InnerText; }
			set { resultdoc.SelectSingleNode(description).InnerText = value; }
		}
#endif
		protected bool want_sms = true;
		private XmlDocument resultdoc;
		/// <summary>The result document</summary>
		/// <value>An XmlDocument containing the result xml/value>
		public XmlDocument Doc {
			get { return resultdoc; }
			set { resultdoc = value; }
		}

		private x_pseudo pseudo;
		/// <summary>PassportX pseudo</summary>
		/// <value>A PassportX pseudo object</value>
		protected x_pseudo _Pseudo { get { return pseudo; } set { pseudo = value; } }
		#endregion

		#region Constructors/Destructors
#if (!USE_X_RESULT)
		protected static readonly ILog _Logger = LogManager.GetLogger(typeof(PassportRootX));

		/// <overloads>Constructors</overloads>
		/// <summary>Default Constructor for older style schemas</summary>
		public PassportRootX() {
			type = PassportTypeX.GateKeeper;
			initialise();
		}
		/// <summary>Constructor for newer style schemas</summary>
		public PassportRootX(string root) {
			tag = root;
			type = PassportTypeX.Passport;
			initialise();
		}
#else
		protected x_logger _Logger;

		/// <overloads>Constructors</overloads>
		/// <summary>Default Constructor for older style schemas</summary>
		public PassportRootX() : base("X", DEFAULT_TAG, typeof(PassportRootX)) {
			_Logger = Logger;
		}
		/// <summary>Constructor for newer style schemas</summary>
		public PassportRootX(string root) : base("X", root, typeof(PassportRootX)) {
			_Logger = Logger;
		}

#endif
		#endregion

		#region Protected methods
#if (!USE_X_RESULT)
		protected void AddSuccess(XmlDocument doc) {
			Doc = doc;
			Doc.LoadXml(string.Format(resultxml, tag, ""));
			Description = "Success";
		}
		protected void AddSuccess(XmlDocument doc, XmlNode thisnode) {
			Doc = doc;
			Doc.LoadXml(string.Format(resultxml, tag, thisnode.InnerXml));
			Description = "Success";
		}
		protected void AddSuccess(XmlDocument doc, string nodexml) {
			Doc = doc;
			Doc.LoadXml(string.Format(resultxml, tag, nodexml));
			Description = "Success";
		}
		protected void AddSuccess(XmlDocument doc, string nodename, string nodeval) {
			Doc = doc;
			Doc.LoadXml(string.Format(resultxml, tag));
			XmlElement newElem = Doc.CreateElement(nodename);
       		newElem.InnerText = nodeval;
			Result.AppendChild(newElem);
			Description = "Success";
		}
		protected void AddFailure(XmlDocument doc, Exception exc, string errcode) {
			Doc = doc;
			Doc.LoadXml(string.Format(resultxml, tag, ""));
			Code = errcode;
			Description = String.Concat("Login error::", exc.Source, ":-:", exc.Message, "::[", exc.StackTrace, "]");
		}
		protected void AddFailure(XmlDocument doc, Exception exc, int errcode) {
			Doc = doc;
			AddFailure(resultdoc, exc, errcode.ToString());
		}
		protected void AddFailure(XmlDocument doc, string errdesc, string errcode) {
			Doc = doc;
			Doc.LoadXml(string.Format(resultxml, tag, ""));
			Code = errcode;
			Description = errdesc;
		}
		protected void AddFailure(XmlDocument doc, string errdesc, int errcode) {
			Doc = doc;
			AddFailure(resultdoc, errdesc, errcode.ToString());
		}
		protected XmlNode AddNode(XmlDocument doc, string nodexml) {
			Doc = doc;
			XmlNode thisnode = Result;
			thisnode.InnerXml = String.Concat(thisnode.InnerXml, nodexml);
			return(thisnode);
		}
		protected XmlNode AddNode(XmlDocument doc, XmlNode thisnode) {
			Doc = doc;
			if (thisnode != null) {	// cannot import null node
				XmlNode newnode = resultdoc.ImportNode(thisnode, true);
				XmlNode resnode = Result;
				resnode.AppendChild(newnode);
				return(resnode);
			}
			else
				return null;
		}
		protected XmlNode AddNode(XmlDocument doc, string nodename, string nodeval) {
			Doc = doc;
			XmlElement newElem = resultdoc.CreateElement(nodename);
       		newElem.InnerText = nodeval;
			XmlNode resnode = Result;
			resnode.AppendChild(newElem);
			return(newElem);
		}
		/// <summary>
		/// Adds an attribute to a node of a document
		/// </summary>
		protected bool AddAttr(XmlDocument xmlThis, XmlNode xnThis, string attname, string attval) {
			try {
				XmlAttribute xaThis = xmlThis.CreateAttribute(attname);
				xaThis.InnerText = attval;
				xnThis.Attributes.Append(xaThis);
				return(true);
			} catch {
				return(false);
			}
		}
		/// <summary>
		/// Method to record the time to a output node (for performance measuring)
		/// </summary>
		protected void SetTime(XmlDocument thisdoc, string mark) {
			DateTime endtime = DateTime.Now;
			TimeSpan timetaken = endtime - starttime;
			string thistime = timetaken.TotalSeconds.ToString();
			AddNode(thisdoc, "Time-" + mark, thistime);
		}
#endif
		#endregion

		#region Public Web methods
#if (!USE_X_RESULT)
		/// <summary>Returns name of service</summary>
		[WebMethod(Description = "Gives the name of the service")]
		public virtual string Name() {
			return tag;
		}

		/// <summary>
		/// Method to test the result.
		/// </summary>
		[WebMethod(Description = "Tests the basic functionality of the web service")]
		public virtual XmlDocument Test() {
			XmlDocument doc = new XmlDocument();
			AddSuccess(doc);
			return doc;
		}
#endif
		#endregion

		#region Private methods
		private string getRequest(Stream receiveStream) {
			StringBuilder thisinp = new StringBuilder();
			try {
	            Encoding encode = Encoding.GetEncoding("utf-8");
	            StreamReader readStream = new StreamReader(receiveStream, encode);
				
	            Char[] read = new Char[1024];
	              // Reads 1024 characters at a time
	            int count = 1, thiscnt = 0;
	            while (count > 0) {
					count = readStream.Read(read, 0, 1024);
					thisinp.Append(read, 0, count);
					thiscnt += count;
            	}
				return thisinp.ToString();
			} catch (Exception e) {
				return String.Concat("Error (getRequest):", e.Message);
			}
		}
		
#if (!USE_X_RESULT)
		private void initialise() {
			setType();
			log4net.Config.XmlConfigurator.Configure();
			//_Logger.Info(String.Concat(Context.Request.ContentType, ",", Context.Request.ServerVariables["SOAPRequest"].ToString()));
			//_Logger.Info(getRequest(Context.Request.InputStream));
			starttime = DateTime.Now;
		}

		private void setType() {
			switch (type) {
				case PassportTypeX.GateKeeper: resultxml = RESULT_XML_GATEKEEPER;
					result = SELECT_RESULT_GATEKEEPER;
					description = SELECT_DESC_GATEKEEPER;
					code = SELECT_CODE_GATEKEEPER;
					break;
				case PassportTypeX.Passport: resultxml = RESULT_XML_PASSPORT;
					result = String.Concat(tag, "/", SELECT_RESULT_PASSPORT);
					description = String.Concat(tag, "/", SELECT_DESC_PASSPORT);
					code = String.Concat(tag, "/", SELECT_CODE_PASSPORT);
					break;
				case PassportTypeX.Other: resultxml = RESULT_XML_OTHER;
					result = SELECT_RESULT_OTHER;
					description = SELECT_DESC_OTHER;
					code = SELECT_CODE_OTHER;
					break;
			}
		}
#endif
		#endregion
	}
}
